﻿namespace EasyToolkit.Excel.UI.BindingTemplate.SortAndFilter.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Input;
    using EasyToolkit.BindingTemplates.Context;
    using EasyToolkit.BindingTemplates.Definitions;
    using EasyToolkit.BindingTemplates.SortAndFilter;
    using EasyToolkit.BindingTemplates.Views;
    using EasyToolkit.UI;
    using EasyToolkit.UI.MvvmBase;

    class SortAndFilterViewModel : ViewModelBase, IDisposable
    {
        #region command
        RelayCommand filterSelectAllCommand;
        public ICommand FilterSelectAllCommand
        { 
            get 
            { 
                return filterSelectAllCommand ?? (filterSelectAllCommand = new RelayCommand(param => { if(selectedDefinition != null && selectedDefinition.ValueSelectionList != null)
                                                                                                            selectedDefinition.ValueSelectionList.ForEach(v => v.IsSelected = true); 
                                                                                                     })); 
            }
        }

        RelayCommand filterUnSelectAllCommand;
        public ICommand FilterUnSelectAllCommand
        {
            get
            {
                return filterUnSelectAllCommand ?? (filterUnSelectAllCommand = new RelayCommand(param => { if (selectedDefinition != null && selectedDefinition.ValueSelectionList != null)
                                                                                                                selectedDefinition.ValueSelectionList.ForEach(v => v.IsSelected = false);
                                                                                                         }));
            }
        }

        RelayCommand applySortAndFilterCommand;
        public ICommand ApplySortAndFilterCommand
        {
            get { return applySortAndFilterCommand ?? (applySortAndFilterCommand = new RelayCommand(param => ApplySortAndFilter()));}
        }

        RelayCommand resetAllCommand;
        public ICommand ResetAllCommand
        {
            get
            {
                return resetAllCommand ?? (resetAllCommand = new RelayCommand(param => { ResetAllFiltersCommand.Execute(null);
                                                                                         ResetAllSortersCommand.Execute(null);}));
            }        
        }

        RelayCommand resetAllFiltersCommand;
        public ICommand ResetAllFiltersCommand
        {
            get
            {
                return resetAllFiltersCommand ?? (resetAllFiltersCommand = new RelayCommand(param => { TemplateViewModels.ForEach(t => t.BindingDefinitions.ForEach(b => { b.IsFilterWithConditions = false;
                                                                                                                                                                           b.IsFilterOnValues = false;}));
                                                                                                     }));
            }        
        }

        RelayCommand resetAllSortersCommand;
        public ICommand ResetAllSortersCommand
        {
            get
            {
                return resetAllSortersCommand ?? (resetAllSortersCommand = new RelayCommand(param => { TemplateViewModels.ForEach(t => t.BindingDefinitions.ForEach(b => { b.IsSortAscending = false;
                                                                                                                                                                           b.IsSortDescending = false;}));
                                                                                                     }));
            }        
        }
        #endregion

        #region properties and attributes
        private IRootTemplateView rootTemplateView;
        //private ISortAndFilter sortAndFilter;

        private TemplateViewModel selectedTemplate;
        public TemplateViewModel SelectedTemplate
        {
            get { return selectedTemplate; }
            set
            {
                selectedTemplate = value;
                OnPropertyChanged("SelectedTemplate");
            }
        }

        public List<TemplateViewModel> TemplateViewModels
        { get; set; }

        private BindingDefinitionViewModel selectedDefinition;
        public BindingDefinitionViewModel SelectedDefinition
        {
            get { return selectedDefinition; }
            set
            {
                selectedDefinition = value;
                OnPropertyChanged("SelectedDefinition");
                FilterChanged();
            }
        }

        public bool SelectedDefinitionFilterOnValueEnabled
        {
            get { return selectedDefinition != null && selectedDefinition.IsFilterOnValues; }
        }

        public bool SelectedDefinitionHasFilterOnValue
        {
            get { return ! SelectedDefinitionHasFilterOnCondition; }
        }

        public bool SelectedDefinitionHasFilterOnCondition
        {
            get { return selectedDefinition != null && selectedDefinition.IsFilterWithConditions; }
        }
        #endregion

        #region .ctors 
        public SortAndFilterViewModel(IRootTemplateView rootTemplateView)
        {
            this.rootTemplateView = rootTemplateView;

            TemplateViewModels = new List<TemplateViewModel>();
            PopulateTemplates(this.rootTemplateView.TemplateDefinition, new IBindingContext[] {this.rootTemplateView.BindingContext});
        }
        #endregion

        #region methods
        private void PopulateTemplates(ITemplateDefinition templateDefinition, IEnumerable<IBindingContext> bindingContexts)
        {
            IEnumerable<IBindingContextElement> elements = bindingContexts.SelectMany(e => e.Elements)
                                                                          .Where(e => e != null);
            if(elements.Count() > 0)
            {
                IEnumerable<IBindingContextItem> items = elements.SelectMany(e => e.BindingContextItems);
                if (templateDefinition.IsSortableAndFilterable)
                {
                    TemplateViewModel templateViewModel = new TemplateViewModel(this, templateDefinition, items);
                    TemplateViewModels.Add(templateViewModel);
                }

                foreach (ILinkedTemplateDefinition childTemplate in templateDefinition.LinkedTemplates)
                {
                    IEnumerable<IBindingContext> childContexts = elements.SelectMany(e => e.LinkedBindingContexts)
                                                                         .Where(e => e.TemplateDefinition.Name.Equals(childTemplate.TemplateDefinition.Name));

                    if (bindingContexts.Count() > 0)
                        PopulateTemplates(childTemplate.TemplateDefinition, childContexts);
                }
            }
        }

        private void ApplySortAndFilter()
        {
            Dictionary<ITemplateDefinition, ISortAndFilter> sortAndFilters = new Dictionary<ITemplateDefinition, ISortAndFilter>();
            foreach(TemplateViewModel template in TemplateViewModels)
            {
                ISortAndFilter sortAndFilter = template.GetSortAndFilter();
                if (sortAndFilter != null)
                    sortAndFilters[template.TemplateDefinition] = sortAndFilter; 
            }
            if (sortAndFilters.Count > 0)
                rootTemplateView.SortsAndFilters = sortAndFilters;
            else
                rootTemplateView.SortsAndFilters = null;

            rootTemplateView.SetDataSource(rootTemplateView.GetDataSource());
            ((RootTemplateView) rootTemplateView).Render();
            MetroFormWpfContainer.CloseWindowCommandRouted.Execute(null, null);
        }

        public void FilterChanged()
        {
            OnPropertyChanged("SelectedDefinitionHasFilterOnValue");
            OnPropertyChanged("SelectedDefinitionFilterOnValueEnabled");
            OnPropertyChanged("SelectedDefinitionHasFilterOnCondition");
        }

        public void Dispose()
        {
            TemplateViewModels.ForEach(t => t.Dispose());
        }
        #endregion
    }
}
